#ifndef PATH_FINDER_HPP
#define PATH_FINDER_HPP

#include "wolf.hpp"
#include <SDL_gfxPrimitives.h>
#include "path_app.hpp"
#include "messages.hpp"
#include "path_map.hpp"
#include "path_alg.hpp"
#include "algorithms.hpp"

using namespace wolf;
/**
 * @brief The main class
 *
 * @since 2010-07-23-??.??
 *
 **/
class PathFinder: public Console
{
public:
    PathFinder(): Console( 25, 100, &_font ), _map( 25, 50 )
    {
        setColor( 0x000000FF );
        setOffsetX( 0 );
        setOffsetY( 400 );
        callApp( _app );
        _mode = EDIT;
        _selecting = false;
        _pencil = true;
        _map.walk(EAST);
        _map.walk(SOUTH);
        _map.walk(EAST);
        _map.walk(EAST);
        _map.walk(NORTH);
        _map.walk(WEST);
        _map.walk(EAST);
        _map.walk(EAST);
        _alg = NULL;
    }
    ~PathFinder()
    {
        //pass;
    }

    /**
     * @brief happens when an SDL_Event occurs
     *
     * It actually just uses the behavor inherited from console, adding an filter on SDLK_F12 that
     *  just turns on or off the console (if was on, turns off, and vice-versa).
     **/
    bool onEvent( Engine &engine, SDL_Event &event )
    {
        if( Console::onEvent( engine, event ) )
        {
            if( event.type == SDL_MOUSEBUTTONDOWN )
            {
                switch(_mode)
                {
                case EDIT:
                    _selection = Rect( event.button.x, event.button.y, 0, 0 );
                    _selecting = true;
                    break;
                case SET_DESTINY:
                    if(event.button.y < 400)
                    {
                        _map.dX(event.button.x / 16);
                        _map.dY(event.button.y / 16);
                    }
                    break;
                case SET_SOURCE:
                    if(event.button.y < 400)
                    {
                        _map.sX(event.button.x / 16);
                        _map.sY(event.button.y / 16);
                    }
                    break;
                default:
                    break;
                }
            }
            else if( event.type == SDL_MOUSEMOTION && _selecting )
            {
                _selection.setX2( event.motion.x );
                _selection.setY2( event.motion.y );
            }
            else if( event.type == SDL_MOUSEBUTTONUP && _mode == EDIT )
            {
                _selecting = false;
                unsigned lmin = min( _selection.getY(), _selection.getY2() ) / 16;
                unsigned lmax = max( _selection.getY(), _selection.getY2() ) / 16 + 1;
                unsigned cmin = min( _selection.getX(), _selection.getX2() ) / 16;
                unsigned cmax = max( _selection.getX(), _selection.getX2() ) / 16 + 1;
                for( unsigned i = lmin; i < lmax; ++i )
                {
                    for( unsigned j = cmin; j < cmax; ++j )
                    {
                        if( _pencil )
                            _map( i, j ) |= BLOCK;
                        else
                            _map( i, j ) &= ~BLOCK;
                    }
                }
                _selection = Rect();
            }
        }
        return false;
    }

    /**
     * @brief Draws the screen
     **/
    void onDraw( Engine &engine, SDL_Surface *dst )
    {
        //Background Draw
        SDL_Rect rect = { 0, 0, 800, 398 };
        SDL_FillRect( dst, &rect, Color( 224, 224, 224 ).toPixel( dst->format ) );
        rect = SDL_Rect{ 0, 400, 800, 200 };
        SDL_FillRect( dst, &rect, Color( 96, 96, 96 ).toPixel( dst->format ) );
        //Console Draw
        Console::onDraw( engine, dst );
        //Grid Draw
        for( int i = 15; i < 400; i += 16 )
        {
            hlineColor( dst, 0, 800, i, Color( 0, 0, 0 ).toHex() );
        }
        for( int i = 15; i < 800; i += 16 )
        {
            vlineColor( dst, i, 0, 400, Color( 0, 0, 0 ).toHex() );
        }
        // Draw map source and destiny

        rect = Rect( _map.sX() * 16, _map.sY() * 16, 15, 15 )();
        SDL_FillRect( dst, &rect, Color( 0, 255, 192 ).toPixel( dst->format ) );
        rect = Rect( _map.dX() * 16, _map.dY() * 16, 15, 15 )();
        SDL_FillRect( dst, &rect, Color( 0, 192, 255 ).toPixel( dst->format ) );
        //Draw map blocks
        const unsigned nLines = _map.nLines();
        const unsigned nCols = _map.nCols();
        for( unsigned i = 0; i < nLines; ++i )
        {
            for( unsigned j = 0; j < nCols; ++j )
            {
                Uint8 pos = _map( i, j );
                if( pos & BLOCK )
                {
                    rect = SDL_Rect{ (Sint16)(j * 16), (Sint16)(i * 16), 15, 15 };
                    Color blockColor( 0, 127, 127 );
                    SDL_FillRect( dst, &rect, blockColor.toPixel( dst->format ) );
                }
                if(pos & MARKED)
                {
                    filledTrigonColor(dst, j*16+7, i*16, j*16, i*16+7,j*16+14, i*16+7, Color(192,192,0,255).toHex());
                    filledTrigonColor(dst, j*16+7, i*16+14, j*16, i*16+7,j*16+14, i*16+7, Color(192,192,0,255).toHex());
//                    boxColor(dst, j*16, i*16, j*16+14, i*16+14,);
                }
                if(pos & LK_EAST)
                {
                    if(pos & VISITED || _map(i, j+1) & VISITED)
                    {
                        boxColor(dst, j*16+8, i*16+7, j*16+24, i*16+9, Color(127,127,127).toHex());
                    }
                    else
                    {
                        boxColor(dst, j*16+8, i*16+7, j*16+24, i*16+9, Color(255,63,63).toHex());
                    }
                }
                if(pos & LK_SOUTH)
                {
                    if(pos & VISITED || (_map(i+1, j)&VISITED) )
                    {
                        boxColor(dst, j*16+7, i*16+8, j*16+9, i*16+24, Color(127,127,127).toHex());
                    }
                    else
                    {
                        boxColor(dst, j*16+7, i*16+8, j*16+9, i*16+24, Color(255,63,63).toHex());
                    }
                }
            }
        }
        //Draw selection
        if( _mode == EDIT )
            boxColor( dst, _selection.getX(), _selection.getY(), _selection.getX2(), _selection.getY2(), Color( 255, 127, 0, 127 ).toHex() );
    }

    /**
     * @brief Verifies messages
     **/
    void onFrame( Engine &engine )
    {
        //Refreshing the algorithims
        if(_mode == RUN)
        {
            _alg->step(_map);
        }
        //Capturing the app messages;
        ConsoleMessage *message;
        while( ( message = receiveMessage() ) != NULL )
        {
            switch ( message->getType() )
            {
                case MESS_EXIT:
                    waitApp();
                    engine.halt();
                    break;
                case MESS_EDIT:
                    _mode = EDIT;
                    break;
                case MESS_RUN:
                    _mode = RUN;
                    delete _alg;
                    _alg = reinterpret_cast<PathAlg*> (message->getData());
                    _map.reset();
                    _alg->init(_map);
                    break;
                case MESS_PENCIL:
                    _pencil = true;
                    break;
                case MESS_ERASER:
                    _pencil = false;
                    break;
                case MESS_SOURCE:
                    _mode = SET_SOURCE;
                    break;
                case MESS_DESTINY:
                    _mode = SET_DESTINY;
                    break;
                default:
                    break;
            }
            refreshStatus();
            delete message;
        }
    }
    void refreshStatus( void )
    {
        stringstream s;
        s << "Path Finder - ";
        if( _mode == EDIT )
        {
            s << "Edit Mode: " << ( _pencil ? "pencil" : "eraser" );
        }
        else if(_mode == SET_SOURCE)
        {
            s << "Click on source position";
        }
        else if(_mode == SET_DESTINY)
        {
            s << "Click on destiny position";
        }
        else if(_mode == RUN) s << "Run Mode";
        SDL_WM_SetCaption( s.str().c_str(), NULL );
    }
private:

    enum Modes
    {
        EDIT,
        SET_SOURCE,
        SET_DESTINY,
        RUN
    } _mode;


    void mode( Modes m )
    {
        _mode = m;
        _selecting = false;
        if( m == EDIT )
        {
            _selection = Rect();
        }
    }
    Rect _selection;
    bool _selecting;
    bool _pencil; ///< If active, draw blocks, otherwise, erase blocks;
    StdFont _font;
    PathApp _app;
    Map _map;
    PathAlg *_alg;
};


#endif // PATH_FINDER_HPP
